/***************************************************************
 * @file           ringbuffer.c
 * @brief
 * @author         WKJay
 * @Version
 * @Date           2024-01-23
 ***************************************************************/
#include <stdio.h>
#include "ringbuffer.h"

uint32_t ringbuffer_data_len_get(ringbuffer_t *rb) {
    if (rb->read_index == rb->write_index) {
        if (rb->read_mirror == rb->write_mirror) {
            return 0;
        } else {
            return rb->buffer_size;
        }
    } else if (rb->read_index < rb->write_index) {
        return rb->write_index - rb->read_index;
    } else {
        return rb->buffer_size - rb->read_index + rb->write_index;
    }
}

int ringbuffer_init(ringbuffer_t *rb, uint8_t *buffer, uint32_t size) {
    if (rb == NULL || buffer == NULL || size == 0) {
        return -1;
    }
    rb->buffer = buffer;
    rb->buffer_size = size;
    rb->read_index = 0;
    rb->write_index = 0;
    rb->read_mirror = 0;
    rb->write_mirror = 0;

    return 0;
}

int ringbuffer_reset(ringbuffer_t *rb) {
    if (rb == NULL) {
        return -1;
    }
    rb->read_index = 0;
    rb->write_index = 0;
    rb->read_mirror = 0;
    rb->write_mirror = 0;

    return 0;
}

int ringbuffer_putchar(ringbuffer_t *rb, uint8_t ch) {
    if (rb == NULL) {
        return -1;
    }

    if (ringbuffer_data_len_get(rb) == rb->buffer_size) {
        // ringbuffer is full
        return -1;
    }

    rb->buffer[rb->write_index] = ch;

    if (rb->write_index == rb->buffer_size - 1) {
        rb->write_index = 0;
        rb->write_mirror = ~rb->write_mirror;
    } else {
        rb->write_index++;
    }

    return 0;
}

int ringbuffer_getchar(ringbuffer_t *rb, uint8_t *ch) {
    if (rb == NULL || ch == NULL) {
        return -1;
    }

    if (ringbuffer_data_len_get(rb) == 0) {
        // ringbuffer is empty
        return -1;
    }

    *ch = rb->buffer[rb->read_index];

    if (rb->read_index == rb->buffer_size - 1) {
        rb->read_index = 0;
        rb->read_mirror = ~rb->read_mirror;
    } else {
        rb->read_index++;
    }

    return 0;
}
